package com.remote.client;

import com.remote.common.DefaultRemoteFactory;
import com.remote.common.RemoteConfiguration;
import com.remote.common.RemoteFactory;
import com.remote.common.context.AbstractRemoteContext;
import com.remote.common.context.RemoteChannelInitializer;
import com.remote.common.context.listener.CloseListener;
import com.remote.common.context.listener.ConnectListener;
import com.remote.common.exception.RemoteException;
import com.remote.common.model.Request;
import com.remote.common.model.Response;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.rmi.server.RemoteServer;

public class RemoteClient extends AbstractRemoteContext {
    private static final Logger LOGGER = LoggerFactory.getLogger(RemoteServer.class);
    private NioEventLoopGroup boss;
    private Bootstrap bootstrap;


    public RemoteClient(RemoteConfiguration remoteConfiguration) {
        this(new DefaultRemoteFactory(remoteConfiguration));
    }

    public RemoteClient(RemoteFactory remoteFactory) {
        super(remoteFactory);

    }

    @Override
    public Channel onConnect() throws RemoteException {
        try {
            String host = this.getRemoteFactory().getRemoteConfiguration().getHost();
            int port = this.getRemoteFactory().getRemoteConfiguration().getPort();

            final ChannelFuture connectFuture = bootstrap.connect(host, port).sync();
            Channel channel = connectFuture.channel();

            connectFuture.addListeners().addListeners(new GenericFutureListener<Future<? super Void>>() {
                @Override
                public void operationComplete(Future<? super Void> future) throws Exception {
                    for (ConnectListener connectListener : getConnectListeners()) {
                        connectListener.onConnect(channel);
                    }
                }
            });
            channel.closeFuture().addListeners(new GenericFutureListener<Future<? super Void>>() {
                @Override
                public void operationComplete(Future<? super Void> future) throws Exception {
                    for (CloseListener closeListener : getCloseListeners()) {
                        closeListener.onClose(channel);
                    }
                }
            });
            return channel;
        } catch (InterruptedException e) {
            throw new RemoteException(e);
        }
    }

    @Override
    protected void initBootstrap() {
        if (this.getEncoderClass() == null) {
            this.setEncoderClass(Request.class);
        }
        if (this.getDecoderClass() == null) {
            this.setDecoderClass(Response.class);
        }
        if (this.getChannelHandler() == null) {
            this.setChannelHandler(new ClientChannelHandler(this));
        }
        if (this.getChannelInitializer() == null) {
            this.setChannelInitializer(new RemoteChannelInitializer());
        }
        this.boss = new NioEventLoopGroup();
        this.bootstrap = new Bootstrap();
        this.bootstrap.group(boss)
                .channel(NioSocketChannel.class)
                .handler(this.getChannelInitializer());
    }



    @Override
    public void close() {

    }

    @Override
    public void refresh() {

    }
}
